package com.lfz.demo.controller;


import com.lfz.demo.common.enums.CensusTimeEnum;
import com.lfz.demo.entity.ChinaPopulation;
import com.lfz.demo.entity.ChinaTotal;
import com.lfz.demo.service.ChinaTotalService;
import com.lfz.demo.service.IndexService;
import com.lfz.demo.utils.RedisUtil;
import com.lfz.demo.vo.DataView;
import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.text.DecimalFormat;
import java.util.*;
import java.util.function.Function;

/**
 * @author lfz
 * @date 2025/2/24 18:08
 * 类职责：控制器层，处理数据查询请求（如整合数据、分页、图表数据等），并集成Redis缓存优化性能。
 * 依赖注入：
 * IndexService：数据查询服务（如分页、按普查时间查询）。
 * ChinaTotalService：中国总人口数据服务。
 * RedisUtil：Redis工具类，用于缓存操作。
 * 常量：
 * CACHE_EXPIRE：缓存过期时间（60分钟）。
 * CACHE_PREFIX：缓存键前缀，避免键冲突。
 */
@RestController
public class IndexController {
    private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);

    @Autowired
    private IndexService indexService;
    @Autowired
    private ChinaTotalService chinaTotalService;

    @Autowired
    private RedisUtil redisUtil;

    // 缓存时间常量（单位：分钟）
    private static final int CACHE_EXPIRE = 60; //缓存过期时间（60分钟）。
    private static final String CACHE_PREFIX = "index:"; //缓存键前缀，避免键冲突。

//    @GetMapping("/query0")
//    public List<ChinaPopulation> queryData(){
//        Jedis jedis = null;
//        List<ChinaPopulation> dataList = new ArrayList<>();
//        try {
//            // 创建 Jedis 连接
//            jedis = new Jedis("127.0.0.1", 6379);
//            // 尝试连接 Redis 服务器
//            jedis.ping();
//
//            // 判断缓存里面有无数据，有 redis 缓存，直接返回
//            List<String> listRedis = jedis.lrange("populationData", 0, 33);
//            if (listRedis.size() > 0) {
//                // 获取存储的数据并输出
//                for (String s : listRedis) {
//                    try {
//                        JSONObject jsonObject = JSONObject.parseObject(s);
//                        Object name = jsonObject.get("cityName");
//                        Object value = jsonObject.get("population");
//                        ChinaPopulation populationData = new ChinaPopulation();
//                        populationData.setCityName(String.valueOf(name));
//                        populationData.setPopulation(Integer.parseInt(value.toString()));
//                        dataList.add(populationData);
//                    } catch (Exception e) {
//                        // 处理 JSON 解析异常
//                        System.err.println("JSON 解析异常: " + e.getMessage());
//                    }
//                }
//                // 查询的 redis 缓存数据库 返回的数据
//                return dataList;
//            } else {
//                // 键不存在，查 mysql 数据库，更新缓存
//                dataList = indexService.list();
//                // 遍历集合
//                for (ChinaPopulation populationData : dataList) {
//                    jedis.lpush("populationData", JSONObject.toJSONString(populationData));
//                }
//                // 返回的数据库中的数据
//                return dataList;
//            }
//        } catch (Exception e) {
//            // 处理 Redis 连接异常或其他异常
//            System.err.println("Redis 连接异常: " + e.getMessage());
//            // 当 Redis 连接失败时，直接查询 MySQL 数据库
//            dataList = indexService.list();
//        } finally {
//            // 释放 Jedis 连接
//            if (jedis != null) {
//                jedis.close();
//            }
//        }
//        return dataList;
//    }

    /**
     * 中国人口数据地图
     */
/*    @GetMapping("/query")
    public Map<String, List<Map<String, Object>>> queryChinaPopulation(){
        // 查询所有的城市名称，常住人口，普查时间描述
        List<ChinaPopulation> chinaPopulationList = indexService.findChinaPopulation();

        // 用于按 censusTime 分组的 Map
        Map<String, List<Map<String, Object>>> resultMap = new HashMap<>();
        for (ChinaPopulation population : chinaPopulationList) {
            String censusTimeCode = String.valueOf(population.getCensusTime().getCode());

            // 如果该普查时间还没有对应的列表，创建一个新的列表
            resultMap.computeIfAbsent(censusTimeCode, k -> new ArrayList<>());

            // 创建每个城市的人口信息 Map
            Map<String, Object> cityData = new HashMap<>();
            cityData.put("cityName", population.getCityName());
            cityData.put("population", population.getPopulation());
            cityData.put("censusTime", censusTimeCode);
            cityData.put("censusDesc", population.getCensusTime().getDesc());

            // 将城市信息添加到对应普查时间的列表中
            resultMap.get(censusTimeCode).add(cityData);
        }

        return resultMap;
    }*/

    /**
     * 按普查时间查询分组数据
     */
   /* @GetMapping("/queryGroupedDataByCensusTime")
    public Map<String,List<Map<String, Object>>> queryGroupedDataByCensusTime() {
        // 查询每次的总人口，出生人口，死亡人口，普查时间描述
        List<ChinaTotal> chinaPopulationList2 = chinaTotalService.list();

        // 用于按 censusTime 分组的 Map
        Map<String, List<Map<String, Object>>> resultMap = new HashMap<>();

        for (ChinaTotal total : chinaPopulationList2) {
            String censusTimeCode = String.valueOf(total.getCensusTime().getCode());

            // 如果该普查时间还没有对应的列表，创建一个新的列表
            resultMap.computeIfAbsent(censusTimeCode, k -> new ArrayList<>());

            // 创建每次普查的人口信息 Map
            Map<String, Object> populationData = new HashMap<>();
            populationData.put("totalPopulation", total.getTotalPopulation());
            populationData.put("totalBirthNum", total.getTotalBirthNum());
            populationData.put("totalDeadNum", total.getTotalDeadNum());
            populationData.put("censusTime", censusTimeCode);
            populationData.put("censusDesc", total.getCensusTime().getDesc());

            // 将人口普查信息添加到对应普查时间的列表中
            resultMap.get(censusTimeCode).add(populationData);
        }
        return resultMap;
    }*/

    /**
     * 整合中国人口数据，包含各城市人口和全国普查统计数据（带Redis缓存）
     */
    @GetMapping("/queryIntegratedData")
    public Map<String, Map<String, Object>> queryIntegratedData() {
        String cacheKey = CACHE_PREFIX + "integratedData";

        try {
            // 尝试从Redis获取缓存
            Object cachedData = redisUtil.get(cacheKey);
            if (cachedData != null) {
                return (Map<String, Map<String, Object>>) cachedData;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Redis连接异常，降级到MySQL查询", e);
        }

        try {
            // 查询所有的城市名称，常住人口，普查时间描述
            List<ChinaPopulation> chinaPopulationList = indexService.findChinaPopulation();
            // 查询每次的总人口，出生人口，死亡人口，普查时间描述
            List<ChinaTotal> chinaTotalList = chinaTotalService.list();

            // 按普查时间分组城市数据
            Map<String, List<Map<String, Object>>> cityDataByCensusTime = groupDataByCensusTime(chinaPopulationList, population -> {
                String censusTimeCode = String.valueOf(population.getCensusTime().getCode());
                Map<String, Object> cityData = new HashMap<>();
                cityData.put("cityName", population.getCityName());
                cityData.put("population", population.getPopulation());
                cityData.put("censusTime", censusTimeCode);
                cityData.put("censusDesc", population.getCensusTime().getDesc());
                return cityData;
            });

            // 按普查时间分组全国统计数据
            Map<String, List<Map<String, Object>>> totalDataByCensusTime = groupDataByCensusTime(chinaTotalList, total -> {
                String censusTimeCode = String.valueOf(total.getCensusTime().getCode());
                Map<String, Object> populationData = new HashMap<>();

                // 计算自然增长率，结果以千分比表示
                double oldNetPopulationGrowth = ((double) (total.getTotalBirthNum() - total.getTotalDeadNum()) / total.getTotalPopulation()) * 1000;
                // 使用 DecimalFormat 保留三位小数
                DecimalFormat df = new DecimalFormat("#.###");
                String NetPopulationGrowth = df.format(oldNetPopulationGrowth);

                populationData.put("totalPopulation", total.getTotalPopulation());
                populationData.put("totalBirthNum", total.getTotalBirthNum());
                populationData.put("totalDeadNum", total.getTotalDeadNum());
                populationData.put("netPopulationGrowth", NetPopulationGrowth);
                populationData.put("updateTime", total.getUpdateTime());
                populationData.put("censusTime", censusTimeCode);
                populationData.put("censusDesc", total.getCensusTime().getDesc());
                return populationData;
            });

            // 整合数据
            Map<String, Map<String, Object>> integratedData = new HashMap<>();
            for (String censusTimeCode : cityDataByCensusTime.keySet()) {
                Map<String, Object> combinedData = new HashMap<>();
                combinedData.put("cities", cityDataByCensusTime.get(censusTimeCode));
                if (totalDataByCensusTime.containsKey(censusTimeCode)) {
                    combinedData.putAll(totalDataByCensusTime.get(censusTimeCode).get(0));
                }
                integratedData.put(censusTimeCode, combinedData);
            }

            // 缓存结果
            redisUtil.set(cacheKey, integratedData, CACHE_EXPIRE);
            return integratedData;
        } catch (Exception e) {
            // 处理异常，可根据实际情况进行日志记录和返回错误信息
            e.printStackTrace();
            logger.error("整合数据查询异常", e);
            return new HashMap<>();
        }
    }

    /**
     * 根据普查时间查询数据并按常住人口从多到少排序，支持分页（带Redis缓存）
     */
    @GetMapping("/listDataByPage")
    public DataView listDataByPage(@RequestParam("censusTime") String censusTime) {
        String cacheKey = CACHE_PREFIX + "listData:" + censusTime;

        try {
            DataView cachedData = (DataView) redisUtil.get(cacheKey);
            if (cachedData != null) {
                return cachedData;
            }
        } catch (Exception e) {
            logger.error("Redis连接异常，降级到MySQL查询", e);
        }
        try {
            List<ChinaPopulation> byCensusTime = indexService.findByCensusTime(censusTime);
            DataView dataView = new DataView((long) byCensusTime.size(),byCensusTime);

            redisUtil.set(cacheKey, dataView, CACHE_EXPIRE);
            return dataView;
        } catch (Exception e) {
            logger.error("分页查询异常", e);
            return new DataView(0L, Collections.emptyList());
        }
    }



    /**
     * 分组聚合 饼图数据查询（带有redis缓存）
     * SQL: select count(*) from goods group gy type;
     */
    @GetMapping("/queryPie")
    public Map<String, List<Map<String, Object>>> queryPieData() {
        String cacheKey = CACHE_PREFIX + "pieData";

        try {
            Object cachedData = redisUtil.get(cacheKey);
            if (cachedData != null) {
                return (Map<String, List<Map<String, Object>>>) cachedData;
            }
        } catch (Exception e) {
            logger.error("Redis连接异常，降级到MySQL查询", e);
        }

        try {
            List<ChinaPopulation> list = indexService.findChinaPopulation();
            // 分组数据
            Map<String, List<Map<String, Object>>> groupedData =  groupDataByCensusTime(list, population -> {
                String censusTimeCode = String.valueOf(population.getCensusTime().getCode());
                Map<String, Object> cityData = new HashMap<>();
                cityData.put("cityName", population.getCityName());
                cityData.put("population", population.getPopulation());
                cityData.put("updateTime", population.getUpdateTime());
                cityData.put("censusTime", censusTimeCode);
                cityData.put("censusDesc", population.getCensusTime().getDesc());
                return cityData;
            });

            // 设置缓存
            redisUtil.set(cacheKey, groupedData, CACHE_EXPIRE);
            return groupedData;
        } catch (Exception e) {
            logger.error("饼图数据查询异常", e);
            return new HashMap<>();
        }
    }

    /**
     * 柱状图数据查询（带Redis缓存）
     */
    @GetMapping("/queryBar")
    public Map<String, List<Map<String, Object>>> queryBarData() {
        String cacheKey = CACHE_PREFIX + "barData";

        try {
            Object cachedData = redisUtil.get(cacheKey);
            if (cachedData != null) {
                return (Map<String, List<Map<String, Object>>>) cachedData;
            }
        } catch (Exception e) {
            logger.error("Redis连接异常，降级到MySQL查询", e);
        }

        try {
            List<ChinaPopulation> list = indexService.findChinaPopulation();
            redisUtil.set(cacheKey, list, CACHE_EXPIRE);
            Map<String, List<Map<String, Object>>> groupedData = groupDataByCensusTime(list, population -> {
                String censusTimeCode = String.valueOf(population.getCensusTime().getCode());
                Map<String, Object> cityData = new HashMap<>();
                cityData.put("cityName", population.getCityName());
                cityData.put("population", population.getPopulation());
                cityData.put("updateTime", population.getUpdateTime());
                cityData.put("censusTime", censusTimeCode);
                cityData.put("censusDesc", population.getCensusTime().getDesc());
                return cityData;
            });

            // 设置缓存
            redisUtil.set(cacheKey, groupedData, CACHE_EXPIRE);
            return groupedData;
        } catch (Exception e) {
            logger.error("柱状图数据查询异常", e);
            return new HashMap<>();
        }

    }

    /**
     * 近七次人口普查折线图
     * select * from line_trend order by create_time limit 7;
     */
    @GetMapping("/queryLine")
    public Map<String, List<Object>> queryLineData(){
        String cacheKey = CACHE_PREFIX + "lineData";

        try {
            Object cachedData = redisUtil.get(cacheKey);
            if (cachedData != null) {
                return (Map<String, List<Object>>) cachedData;
            }
        } catch (Exception e) {
            logger.error("Redis连接异常，降级到MySQL查询", e);
        }

        try {
            // 1、查询近七次普查人口所有数据
            List<ChinaTotal> list7order = chinaTotalService.findSevenTotalPopulation();
            // 2、声明近七次普查的总人口数的对象数组
            List<Integer> totalPopulationList = new ArrayList<>();
            // 3、声明近七次普查的出生人数的对象数组
            List<Integer> birthNumList = new ArrayList<>();
            // 4、声明近七次普查的死亡人数的对象数组
            List<Integer> deadNumList = new ArrayList<>();
            // 5、声明近七次普查的人口自然增长率的对象数组
            List<String> netPopulationGrowthList = new ArrayList<>();
            // 6、声明近七次普查的普查时间编号的对象数组
            List<Integer> censusTimeCodeList = new ArrayList<>();
            // 6、声明近七次普查的普查时间名称数据的对象数组
            List<String> censusTimeDescList = new ArrayList<>();
            // 7、封装对象信息
            for (ChinaTotal data : list7order) {
                totalPopulationList.add(data.getTotalPopulation());
                birthNumList.add(data.getTotalBirthNum());
                deadNumList.add(data.getTotalDeadNum());

                // 计算自然增长率，结果以千分比表示
                double oldNetPopulationGrowth = ((double) (data.getTotalBirthNum() - data.getTotalDeadNum()) / data.getTotalPopulation()) * 1000;
                // 使用 DecimalFormat 保留三位小数
                DecimalFormat df = new DecimalFormat("#.###");
                String netPopulationGrowth = df.format(oldNetPopulationGrowth);
                netPopulationGrowthList.add(netPopulationGrowth);

                // 获取 普查时间编号 code
                Integer code = data.getCensusTime().getCode();
                censusTimeCodeList.add(code);
                // 根据 code 从枚举中获取描述
                CensusTimeEnum censusTimeEnum = CensusTimeEnum.getByCode(code);
                if (censusTimeEnum != null) {
                    censusTimeDescList.add(censusTimeEnum.getDesc());
                } else {
                    censusTimeDescList.add("未知普查");
                }
            }
            // 8、返回的数据格式容器Map
            Map map = new HashMap<>();
            map.put("totalPopulationList", totalPopulationList);
            map.put("birthNumList", birthNumList);
            map.put("deadNumList", deadNumList);
            map.put("netPopulationGrowthList", netPopulationGrowthList);
            map.put("censusTimeCodeList", censusTimeCodeList);
            map.put("censusTimeDescList", censusTimeDescList);

            redisUtil.set(cacheKey, map, CACHE_EXPIRE);
            return map;
        } catch (Exception e) {
            logger.error("折线图数据查询异常", e);
            return new HashMap<>();
        }
    }


    /**
     * 按普查时间分组数据的公共方法
     * @param dataList 数据列表
     * @param mapper 数据转换函数
     * @param <T> 数据类型
     * @return 按普查时间分组的结果
     */
    private <T> Map<String, List<Map<String, Object>>> groupDataByCensusTime(List<T> dataList, Function<T, Map<String, Object>> mapper) {
        Map<String, List<Map<String, Object>>> resultMap = new HashMap<>();
        for (T data : dataList) {
            Map<String, Object> mappedData = mapper.apply(data);
            String censusTimeCode = (String) mappedData.get("censusTime");
            resultMap.computeIfAbsent(censusTimeCode, k -> new ArrayList<>()).add(mappedData);
        }
        return resultMap;
    }

}
